package org.lewis.demo.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

@Slf4j
@Component
public class RsaUtil {

    /**
     * 生成密钥对
     *
     * @return
     * @throws Exception
     */
    public KeyPair genKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(512);
        return keyGen.generateKeyPair();
    }

    private PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(privateKey.getBytes(StandardCharsets.UTF_8));

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");

        return kf.generatePrivate(keySpec);
    }

    private PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] keyBytes = Base64Utils.decode(publicKey.getBytes(StandardCharsets.UTF_8));

        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");

        return kf.generatePublic(keySpec);
    }

    public void logKeyPair() throws Exception {
        KeyPair keyPair = this.genKeyPair();
        log.info("\nKeyPair:\n  privateKey: {}\n  publicKey: {}",
                new String(Base64Utils.encode(keyPair.getPrivate().getEncoded())),
                new String(Base64Utils.encode(keyPair.getPublic().getEncoded())));
    }

    /**
     * 签名
     *
     * @param content    待签名字符串
     * @param privateKey 签名密钥
     * @return 签名字符串
     * @throws Exception
     */
    public String md5Sign(String content, String privateKey) throws Exception {
        PrivateKey key = this.getPrivateKey(privateKey);
        return this.md5Sign(content, key);
    }

    /**
     * 验签
     *
     * @param content   待验签字符串
     * @param sign      待比较的签名
     * @param publicKey 验签公钥
     * @return 验签结果
     * @throws Exception
     */
    public boolean verifyWhenMd5Sign(String content, String sign, String publicKey) throws Exception {
        PublicKey key = this.getPublicKey(publicKey);
        return this.verifyWhenMd5Sign(content, sign, key);
    }

    /**
     * 签名
     *
     * @param content    待签名字符串
     * @param privateKey 签名密钥
     * @return 签名字符串
     * @throws Exception
     */
    public String md5Sign(String content, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initSign(privateKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return new String(Base64Utils.encode(signature.sign()));
    }

    /**
     * 验签
     *
     * @param content   待验签字符串
     * @param sign      待比较的签名
     * @param publicKey 验签公钥
     * @return 验签结果
     * @throws Exception
     */
    public boolean verifyWhenMd5Sign(String content, String sign, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("MD5withRSA");
        signature.initVerify(publicKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return signature.verify(Base64Utils.decode(sign.getBytes()));
    }

    /**
     * 签名
     *
     * @param content    待签名字符串
     * @param privateKey 签名密钥
     * @return 签名字符串
     * @throws Exception
     */
    public String sha1Sign(String content, String privateKey) throws Exception {
        PrivateKey key = this.getPrivateKey(privateKey);
        return this.sha1Sign(content, key);
    }

    /**
     * 验签
     *
     * @param content   待验签字符串
     * @param sign      待比较的签名
     * @param publicKey 验签公钥
     * @return 验签结果
     * @throws Exception
     */
    public boolean verifyWhenSha1Sign(String content, String sign, String publicKey) throws Exception {
        PublicKey key = this.getPublicKey(publicKey);
        return this.verifyWhenSha1Sign(content, sign, key);
    }

    /**
     * 签名
     *
     * @param content    待签名字符串
     * @param privateKey 签名密钥
     * @return 签名字符串
     * @throws Exception
     */
    public String sha1Sign(String content, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(privateKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return new String(Base64Utils.encode(signature.sign()));
    }

    /**
     * 验签
     *
     * @param content   待验签字符串
     * @param sign      待比较的签名
     * @param publicKey 验签公钥
     * @return 验签结果
     * @throws Exception
     */
    public boolean verifyWhenSha1Sign(String content, String sign, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(publicKey);
        signature.update(content.getBytes(StandardCharsets.UTF_8));
        return signature.verify(Base64Utils.decode(sign.getBytes()));
    }

}
